package utils

import (
	"fmt"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"strings"
)

type RunType string

const (
	// RunTypeUnknown 咱也不知道咋运行的
	RunTypeUnknown = "Unknown"

	// RunTypeSourceCode 是从源代码中运行的
	RunTypeSourceCode = "SourceCode"

	// RunTypeReleaseBinary 发布的二进制文件运行
	RunTypeReleaseBinary = "ReleaseBinary"
)

// GetRunType 获取当前程序是以什么方式运行的
func GetRunType() (RunType, error) {
	executable, err := os.Executable()
	if err != nil {
		return RunTypeUnknown, err
	}
	switch runtime.GOOS {
	case "windows":
		//使用goland启动agr1：\tmp\GoLand\___go_build_hRun_go.exe
		//使用go run hRun_go.go: \Temp\go-build4087509482\b001\exe\hRun.exe
		if strings.Contains(executable, "_go_build") || strings.Contains(executable, "go-build") {
			return RunTypeSourceCode, nil
		} else {
			return RunTypeReleaseBinary, nil
		}
	case "linux":
		// /tmp/go-build1325605723/b001/exe/test
		if strings.HasPrefix(executable, "/tmp/go-build") {
			return RunTypeSourceCode, nil
		} else {
			return RunTypeReleaseBinary, nil
		}
	case "darwin":
		// T/go-build3362823274/b001/exe/main
		if strings.HasSuffix(executable, "/exe/main") && strings.Contains(executable, "/go-build") {
			return RunTypeSourceCode, nil
		} else {
			return RunTypeReleaseBinary, nil
		}
	}
	return RunTypeUnknown, nil
}

// SourceCodeRunType 如果是从源代码运行的话，则入口是啥
type SourceCodeRunType string

const (

	// SourceCodeRunEnterUnknown 只知道是从源代码中运行的，但是入口俺也不知道
	SourceCodeRunEnterUnknown = "Unknown"

	// SourceCodeRunEnterExample 是从Example运行的
	SourceCodeRunEnterExample = "Example"

	// SourceCodeRunEnterBenchmark 是从Benchmark运行的
	SourceCodeRunEnterBenchmark = "Benchmark"

	// SourceCodeRunEnterMain 是从main.go运行的
	SourceCodeRunEnterMain = "main.go"

	// SourceCodeRunEnterTest 是从测试用例运行的
	SourceCodeRunEnterTest = "Test"
)

// GetSourceCodeRunType 如果是从源代码运行的，则是以什么方式运行的
func GetSourceCodeRunType() (SourceCodeRunType, error) {
	stack := string(debug.Stack())
	split := strings.Split(stack, "\n")
	if len(split) < 3 {
		return SourceCodeRunEnterUnknown, nil
	}
	s := split[len(split)-3]
	switch s {
	case "created by testing.(*T).Run":
		return SourceCodeRunEnterTest, nil
	case "created by testing.(*B).run1":
		return SourceCodeRunEnterBenchmark, nil
	case "main.main()":
		if strings.HasPrefix(split[len(split)-2], "\t_testmain.go") {
			return SourceCodeRunEnterExample, nil
		} else {
			return SourceCodeRunEnterMain, nil
		}
	}
	return SourceCodeRunEnterUnknown, nil
}

// RunIDE 是从什么IDE中运行的
type RunIDE int

const (
	// RunIDEUnknown 咱也不知道是啥IDE
	RunIDEUnknown RunIDE = iota
	// RunIDEGoland 是从GoLand中运行的
	RunIDEGoland
)

func (x RunIDE) String() string {
	switch x {
	case RunIDEUnknown:
		return "Unknown"
	case RunIDEGoland:
		return "Goland"
	default:
		return ""
	}
}

func GetRunIDE() (RunIDE, error) {
	executable, err := os.Executable()
	if err != nil {
		return RunIDEUnknown, err
	}
	dir := filepath.Dir(executable)
	switch runtime.GOOS {
	case "windows":
		if strings.Contains(strings.ToLower(dir), "\\tmp\\goland") {
			return RunIDEGoland, nil
		}
	default:
		if strings.HasSuffix(dir, "GoLand") {
			return RunIDEGoland, nil
		}
	}
	return RunIDEUnknown, nil
}

func GetEunPath() string {
	runType, _ := GetRunType()
	switch runType {
	case RunTypeSourceCode:
		dir, _ := os.Getwd()
		return dir
	case RunTypeReleaseBinary:
		return path.Dir(os.Args[0])
	default:
		return ""
	}
}
func GetEunPathAbc() string {
	abs, err := filepath.Abs(GetEunPath())
	if err != nil {
		fmt.Printf("%v\n", err)
	}
	return abs
}
